package cn.zyl.demo.undertow;

import org.xnio.*;
import org.xnio.channels.*;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;

/**
 * XnioSimpleServer类说明:
 * <p><a href="https://www.cnblogs.com/jpfss/p/11320744.html">Undertow服务器基础分析 - XNIO</a></p>
 * <p><a href="http://codemacro.com/2017/04/09/xnio-source/">XNIO源码阅读</a></p>
 *
 * @author z.y.l
 * @version v1.0
 * @date 2020-09-07
 */
public class XnioSimpleServer {
    public static void main(String[] args) throws IOException {
        final ChannelListener<AcceptingChannel<StreamConnection>> channelListener = channel -> {
            StreamConnection accepted;
            try {
                // channel就绪，准备接收连接请求
                while ((accepted = channel.accept())!=null){
                    System.out.println("accepted :"+accepted.getPeerAddress());
                    // 已经连接，设置读数据listener
                    accepted.getSourceChannel().setReadListener(new ReadListener(accepted.getSinkChannel()));
                    // 恢复读的状态
                    accepted.getSourceChannel().resumeReads();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        };
        //创建Xnio实例，并构造XnioWorker
        final XnioWorker worker = Xnio.getInstance().createWorker(OptionMap.EMPTY);
        // 创建server，在本地12345端口上侦听
        AcceptingChannel<? extends StreamConnection> server =
                worker.createStreamConnectionServer(new InetSocketAddress(12345), channelListener, OptionMap.EMPTY);
        // 开始接受连接
        server.resumeAccepts();
        System.out.println("Listening on :" + server.getLocalAddress());
    }
    /**定义读数据listener*/
    static class ReadListener implements ChannelListener<StreamSourceChannel> {
        /** 保存一个可写的channel，才能在读listener里做写操作*/
        private final StreamSinkChannel sinkChannel;
        public ReadListener(StreamSinkChannel sinkChannel) {
            this.sinkChannel = sinkChannel;
        }
        @Override
        public void handleEvent(StreamSourceChannel channel) {
            System.out.println("read-----");
            //分配缓冲
            final ByteBuffer buffer = ByteBuffer.allocate(512);
            int res;
            try {
                while ((res = channel.read(buffer)) > 0) {
                    //切换到写的状态并用阻塞的方式写回
                    buffer.flip();
                    Channels.writeBlocking(sinkChannel, buffer);
                }
                // 保证全部送出
                Channels.flushBlocking(sinkChannel);
                if (res == -1) {
                    channel.close();
                } else {
                    channel.resumeReads();
                }
            } catch (IOException e) {
                e.printStackTrace();
                IoUtils.safeClose(channel);
            }
        }
    }
}
